package jwx

import (
	
	
	
	
	
	
	
	
	
	

	
	
)

// SignClaims signs the given claims using a given key and a method
func ( jwt.Claims,  interface{},  jwt.SigningMethod) (string, error) {
	 := jwt.NewWithClaims(, )
	return .SignedString()
}

// DecodeAccessTokenHeader decodes the header of the accessToken
func ( string) (*DecodedAccessTokenHeader, error) {
	const  = "could not decode access token header"
	 = strings.Replace(, "Bearer ", "", 1)
	 := strings.Split(, ".")
	,  := base64.RawStdEncoding.DecodeString([0])
	if  != nil {
		return nil, errors.Wrap(, )
	}

	 := &DecodedAccessTokenHeader{}
	 = json.Unmarshal(, )
	if  != nil {
		return nil, errors.Wrap(, )
	}

	return , nil
}

func toBigInt( string) (*big.Int, error) {
	,  := base64.RawURLEncoding.DecodeString()
	if  != nil {
		return nil, 
	}

	 := big.NewInt(0)
	.SetBytes()
	return , nil
}

var (
	curves = map[string]elliptic.Curve{
		"P-224": elliptic.P224(),
		"P-256": elliptic.P256(),
		"P-384": elliptic.P384(),
		"P-521": elliptic.P521(),
	}
)

func decodeECDSAPublicKey(, ,  *string) (*ecdsa.PublicKey, error) {
	const  = "could not decode public key"

	,  := toBigInt(*)
	if  != nil {
		return nil, errors.Wrap(, )
	}

	,  := toBigInt(*)
	if  != nil {
		return nil, errors.Wrap(, )
	}
	var  elliptic.Curve
	var  bool
	if ,  = curves[*]; ! {
		return nil, errors.Wrap(fmt.Errorf("unknown curve alg: %s", *), )
	}
	return &ecdsa.PublicKey{X: , Y: , Curve: }, nil
}

func decodeRSAPublicKey(,  *string) (*rsa.PublicKey, error) {
	const  = "could not decode public key"

	,  := toBigInt(*)
	if  != nil {
		return nil, errors.Wrap(, )
	}

	,  := base64.RawURLEncoding.DecodeString(*)
	if  != nil {
		return nil, errors.Wrap(, )
	}

	var  []byte
	if len() < 8 {
		 = make([]byte, 8-len(), 8)
		 = append(, ...)
	} else {
		 = 
	}

	 := bytes.NewReader()
	var  uint64
	 = binary.Read(, binary.BigEndian, &)
	if  != nil {
		return nil, errors.Wrap(, )
	}

	 := rsa.PublicKey{N: , E: int()}
	return &, nil
}

// DecodeAccessTokenRSACustomClaims decodes string access token into jwt.Token
func ( string, ,  *string,  jwt.Claims) (*jwt.Token, error) {
	const  = "could not decode accessToken with custom claims"
	 = strings.Replace(, "Bearer ", "", 1)

	,  := decodeRSAPublicKey(, )
	if  != nil {
		return nil, errors.Wrap(, )
	}

	,  := jwt.ParseWithClaims(, , func( *jwt.Token) (interface{}, error) {
		// Don't forget to validate the alg is what you expect:
		if ,  := .Method.(*jwt.SigningMethodRSA); ! {
			return nil, fmt.Errorf("unexpected signing method: %v", .Header["alg"])
		}
		return , nil
	})

	if  != nil {
		return nil, errors.Wrap(, )
	}
	return , nil
}

// DecodeAccessTokenECDSACustomClaims decodes string access token into jwt.Token
func ( string, , ,  *string,  jwt.Claims) (*jwt.Token, error) {
	const  = "could not decode accessToken"
	 = strings.Replace(, "Bearer ", "", 1)

	,  := decodeECDSAPublicKey(, , )
	if  != nil {
		return nil, errors.Wrap(, )
	}

	,  := jwt.ParseWithClaims(, , func( *jwt.Token) (interface{}, error) {
		// Don't forget to validate the alg is what you expect:
		if ,  := .Method.(*jwt.SigningMethodECDSA); ! {
			return nil, fmt.Errorf("unexpected signing method: %v", .Header["alg"])
		}
		return , nil
	})

	if  != nil {
		return nil, errors.Wrap(, )
	}
	return , nil
}